﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using ZedGraph;

namespace UNSWThink
{
   /*
    * TODO: update new points on graph rather than redo entire graph
    */
   /// <summary>
   /// Windows form used to display responses as a graph
   /// </summary>
   public partial class GraphResponsesForm : Form
   {
      private int questionID;
      private int questionNum;
      private QuestionType questionType;
      private DataTable answers;
      private DataTable responses;

      private ArrayList totals;
      private ArrayList totalsError;
      private int offset;

      /// <summary>
      /// Default constructor
      /// </summary>
      /// <param name="questionID">
      /// ID of the question
      /// </param>
      /// <param name="questionNum">
      /// Question's number
      /// </param>
      /// <param name="questionType">
      /// Question's type
      /// </param>
      /// <param name="answers">
      /// Answers that are related to the selected class
      /// </param>
      /// <param name="responses">
      /// Responses that are related to the selected class
      /// </param>
      public GraphResponsesForm(int questionID, int questionNum, QuestionType questionType, DataTable answers, DataTable responses)
      {
         InitializeComponent();

         this.questionID = questionID;
         this.questionNum = questionNum;
         this.questionType = questionType;
         this.answers = GetRelatedAnswers(answers, questionID);
         this.responses = responses;

         this.totals = new ArrayList();
         this.totalsError = new ArrayList();
         this.offset = 0;
      }

      #region WINDOWS FORM EVENTS

      private void GraphResponsesForm_Load(object sender, EventArgs e)
      {
         // check answers contain expected table column name precondition
         if (HelperMethods.CheckColumnsExists(answers, Defs.ANSWER_COLUMN_NAMES))
         {
            // ResponseTotal list generation determined by the question's type
            if ((questionType == QuestionType.MCQ) || (questionType == QuestionType.OPN))
            {
               for (int i = 0; i < answers.Rows.Count; i++)
               {
                  //if ((int)answers.Rows[i]["question"] == questionID)
                  //{
                     ResponseTotal newTotal = new ResponseTotal(answers.Rows[i]["description"].ToString());
                     totals.Add(newTotal);
                  //}
               }
            }
            else if (questionType == QuestionType.TFQ)
            {
               ResponseTotal newTotal1 = new ResponseTotal("true");
               totals.Add(newTotal1);

               ResponseTotal newTotal2 = new ResponseTotal("false");
               totals.Add(newTotal2);
            }
         }

         // check responses contain expected table column name precondition
         if (HelperMethods.CheckColumnsExists(responses, Defs.RESPONSE_COLUMN_NAMES))
         {
            // loop through responses table to change the totals
            for (int i = 0; i < responses.Rows.Count; i++)
            {
               IncrementTotal(responses.Rows[i]["description"].ToString());
            }
         }

         offset = responses.Rows.Count;

         InitGraph();
      }

      #endregion

      #region HELPER METHODS

      /// <summary>
      /// Initialises the graph to display the totals
      /// </summary>
      private void InitGraph()
      {
         // init various graph properties
         GraphPane myPane = zgc.GraphPane;
         myPane.CurveList.Clear();
         myPane.GraphObjList.Clear();
         BarSettings bs = myPane.BarSettings;

         // TODO: possibly need to have specific case for each question type
         // set the title and axis labels
         myPane.Title.Text = "Responses for Question " + questionNum + " (Right-click on graph for menu)";
         myPane.XAxis.Title.Text = "Totals";
         myPane.YAxis.Title.Text = "Answers";
         String[] labels = HelperMethods.ParseStringArray(totals);
         myPane.YAxis.Scale.TextLabels = labels;
         myPane.YAxis.Type = AxisType.Text;

         // generate point list from totals list
         PointPairList list = new PointPairList();
         foreach (ResponseTotal total in totals)
         {
            list.Add(total.CurrentTotal, 0);
         }

         // create new curve
         BarItem myCurve = myPane.AddBar("", list, Color.Blue);
         myCurve.Bar.Fill = new Fill(Color.Blue, Color.White, Color.Blue, 90);

         // set BarBase to the YAxis for horizontal bars
         myPane.BarSettings.Base = BarBase.Y;

         // fill the chart background with a color gradient
         myPane.Chart.Fill = new Fill(Color.White,
            Color.FromArgb(255, 255, 166), 45.0F);

         // update the axis for current points
         zgc.AxisChange();

         // create TextObj's to provide labels for each bar
         BarItem.CreateBarLabels(myPane, false, "f0");
         zgc.Refresh();
      }

      /// <summary>
      /// Gets related answers
      /// </summary>
      /// <param name="answers">
      /// Data table that contains all of the answers related to the selected class
      /// </param>
      /// <param name="questionID">
      /// ID of the question that is related to the answers
      /// </param>
      /// <returns>
      /// Data table containing all of the related answers with the given question ID
      /// </returns>
      private DataTable GetRelatedAnswers(DataTable answers, int questionID)
      {
         DataTable newTable = new DataTable("RelatedAnswers");

         // add existing answer table column names to the new table
         for (int i = 0; i < answers.Columns.Count; i++)
         {
            string columnName = answers.Columns[i].ColumnName;
            DataColumn newColumn = new DataColumn(columnName, answers.Columns[i].DataType);
            newColumn.ReadOnly = true;
            newTable.Columns.Add(newColumn);
         }

         // copy rows from original table to the new table
         for (int i = 0; i < answers.Rows.Count; i++)
         {
            if (HelperMethods.CheckColumnsExists(answers, new string[1] { "question" }))
            {
               if ((int)answers.Rows[i]["question"] == questionID)
               {
                  object[] values = answers.Rows[i].ItemArray;
                  newTable.Rows.Add(values);
               }
            }
         }

         return newTable;
      }

      /// <summary>
      /// Modifies the ResponseTotal list for a given answer
      /// </summary>
      /// <param name="answerDescription">
      /// The answer which is to be used for the comparison
      /// </param>
      private void IncrementTotal(string answerDescription)
      {
         // search the ResponseTotal list for matching answer
         foreach (ResponseTotal currTotal in totals)
         {
            // if answer matches, increment the currentTotal and return from the method
            if (currTotal.Answer == answerDescription)
            {
               currTotal.CurrentTotal++;
               return;
            }
         }

         // if no match is found, loop through the error ResponseTotal list for matching answer
         foreach (ResponseTotal errTotal in totalsError)
         {
            // if answer matches, increment the currentTotal and return from the method
            if (errTotal.Answer == answerDescription)
            {
               errTotal.CurrentTotal++;
               return;
            }
         }

         // if no match is found, create a new ResponseTotal object and add it to the error
         // ResponseTotal list
         ResponseTotal newError = new ResponseTotal(answerDescription);
         newError.CurrentTotal = 1;
         totalsError.Add(newError);
      }

      /// <summary>
      /// Updates the form's graph with the latest responses
      /// </summary>
      public void UpdateGraph()
      {
         if (offset < responses.Rows.Count)
         {
            if (HelperMethods.CheckColumnsExists(responses, Defs.RESPONSE_COLUMN_NAMES))
            {
               for (int i = offset; i < responses.Rows.Count; i++)
               {
                  IncrementTotal(responses.Rows[i]["description"].ToString());
               }
            }

            offset = responses.Rows.Count;

            InitGraph();
         }
      }

      #endregion
   }
}
